﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Csla;
using Csla.Data;
using System.Data;
using System.Threading;
using Csla.Validation;
using System.Data.Common;
using Microsoft.Practices.EnterpriseLibrary.Data;
using Microsoft.Practices.EnterpriseLibrary.ExceptionHandling;

namespace Asah.SiteWorx.ProductCatalog
{
    [Serializable()]
    public class Product : BusinessBase<Product>
    {

        #region Business Methods

        private int _id = 0;
        private Guid _uniqueId = Guid.NewGuid();
        private string _title = "";
        private string _description = "";
        private string _itemNumber = "";
        private string _dimensions = "";
        private decimal _unitPrice;
        private string _imagePath = "";
        private int _position = -1;
        private Membership.User _createdBy;
        private SmartDate _createdDate;
        private Membership.User _lastUpdatedBy;
        private SmartDate _lastUpdatedDate;

        [System.ComponentModel.DataObjectField(true, true)]
        public int ID
        {
            get
            {
                CanReadProperty("ID", true);
                return _id;
            }
        }

        public Guid UniqueId
        {
            get
            {
                CanReadProperty("UniqueId");
                return _uniqueId;
            }
        }

        public string Title
        {
            get
            {
                CanReadProperty("Title", true);
                return _title;
            }
            set
            {
                CanWriteProperty("Title", true);
                if (_title != value)
                {
                    _title = value;
                    PropertyHasChanged("Title");
                }
            }
        }

        public string Description
        {
            get
            {
                CanReadProperty("Description", true);
                return _description;
            }
            set
            {
                CanWriteProperty("Description", true);
                if (_description != value)
                {
                    _description = value;
                    PropertyHasChanged("Description");
                }
            }
        }

        public string ItemNumber
        {
            get
            {
                CanReadProperty("ItemNumber", true);
                return _itemNumber;
            }
            set
            {
                CanWriteProperty("ItemNumber", true);
                if (_itemNumber != value)
                {
                    _itemNumber = value;
                    PropertyHasChanged("ItemNumber");
                }
            }
        }

        public string Dimensions
        {
            get
            {
                CanReadProperty("Dimensions", true);
                return _dimensions;
            }
            set
            {
                CanWriteProperty("Dimensions", true);
                if (_dimensions != value)
                {
                    _dimensions = value;
                    PropertyHasChanged("Dimensions");
                }
            }
        }

        public decimal UnitPrice
        {
            get
            {
                CanReadProperty("UnitPrice", true);
                return _unitPrice;
            }
            set
            {
                CanWriteProperty("UnitPrice", true);
                if (_unitPrice != value)
                {
                    _unitPrice = value;
                    PropertyHasChanged("UnitPrice");
                }
            }
        }

        public string ImagePath
        {
            get
            {
                CanReadProperty("ImagePath", true);
                return _imagePath;
            }
            set
            {
                CanWriteProperty("ImagePath", true);
                if (_imagePath != value)
                {
                    _imagePath = value;
                    PropertyHasChanged("ImagePath");
                }
            }
        }

        public int Position
        {
            get
            {
                CanReadProperty("Position", true);
                return _position;
            }
            set
            {
                CanWriteProperty("Position", true);
                if (_position != value)
                {
                    _position = value;
                    PropertyHasChanged("Position");
                }
            }
        }

        public Membership.User CreatedBy
        {
            get
            {
                CanReadProperty("CreatedBy", true);
                return _createdBy;
            }
        }

        public string CreatedDate
        {
            get
            {
                CanReadProperty("CreatedDate", true);
                return _createdDate.ToString("g");
            }
        }

        public Membership.User LastUpdatedBy
        {
            get
            {
                CanReadProperty("LastUpdatedBy", true);
                return _lastUpdatedBy;
            }
        }

        public string LastUpdatedDate
        {
            get
            {
                CanReadProperty("LastUpdatedDate", true);
                return _lastUpdatedDate.ToString("g");
            }
        }

        protected override object GetIdValue()
        {
            return _id;
        }

        #endregion

        #region Validation Rules

        protected override void AddBusinessRules()
        {
            // add BusinessRules here
            ValidationRules.AddInstanceRule(CheckTitle, "Title");
        }

        private bool CheckTitle(object target, Csla.Validation.RuleArgs e)
        {
            if (_title.Length > 0)
            {
                return true;
            }
            else
            {
                e.Description = "Product title is required.";
                return false;
            }
        }

        #endregion

        #region Authorization Rules

        protected override void AddAuthorizationRules()
        {
            // add AuthorizationRules here
        }

        public static bool CanAddProduct()
        {
            return true;
        }

        public static bool CanGetProduct()
        {
            return true;
        }

        public static bool CanDeleteProduct()
        {
            return true;
        }

        public static bool CanEditCatalog()
        {
            return true;
        }

        #endregion

        #region Factory Methods

        internal static Product NewProduct()
        {
            return new Product();
        }

        internal static Product GetProduct(SafeDataReader dr)
        {
            return new Product(dr);
        }

        private Product()
        {
            MarkAsChild();
            ValidationRules.CheckRules();
        }

        private Product(SafeDataReader dr)
        {
            MarkAsChild();
            Fetch(dr);
        }

        #endregion

        #region Data Access

        private void Fetch(SafeDataReader dr)
        {
            _id = dr.GetInt32("ProductId");
            _title = dr.GetString("Title");
            _description = dr.GetString("Description");
            _itemNumber = dr.GetString("ItemNumber");
            _dimensions = dr.GetString("Dimensions");
            _unitPrice = dr.GetDecimal("UnitPrice");
            _imagePath = dr.GetString("ImagePath");
            _position = dr.GetInt32("Position");
            _createdBy = Membership.User.GetUser(dr.GetGuid("CreatedBy"));
            _createdDate = dr.GetSmartDate("CreatedDate");
            _lastUpdatedBy = Membership.User.GetUser(dr.GetGuid("LastUpdatedBy"));
            _lastUpdatedDate = dr.GetSmartDate("LastUpdatedDate");

            MarkOld();
            ValidationRules.CheckRules();
        }

        internal void Insert(Catalog catalog)
        {
            // if we're not dirty then don't update the database
            if (!this.IsDirty) return;

            Database db = DatabaseFactory.CreateDatabase("SiteWorx");
            DbCommand dbCommand = db.GetStoredProcCommand("aspnet_Products_AddProduct");
            db.AddInParameter(dbCommand, "ApplicationId", DbType.Guid, Site.GetSite().ApplicationId);
            db.AddInParameter(dbCommand, "ProductCatalogId", DbType.Int32, catalog.ID);
            db.AddInParameter(dbCommand, "Title", DbType.String, _title);
            db.AddInParameter(dbCommand, "Description", DbType.String, _description);
            db.AddInParameter(dbCommand, "ItemNumber", DbType.String, _itemNumber);
            db.AddInParameter(dbCommand, "Dimensions", DbType.String, _dimensions);
            db.AddInParameter(dbCommand, "UnitPrice", DbType.Currency, _unitPrice);
            db.AddInParameter(dbCommand, "ImagePath", DbType.String, _imagePath);
            db.AddInParameter(dbCommand, "Position", DbType.Int32, _position);
            db.AddInParameter(dbCommand, "CreatedBy", DbType.Guid, Membership.User.GetUser(Thread.CurrentPrincipal.Identity.Name).ID);
            db.AddInParameter(dbCommand, "CreatedDate", DbType.DateTime, DateTime.Now);
            
            try
            {
                _id = int.Parse(db.ExecuteScalar(dbCommand).ToString());
                dbCommand.Dispose();
            }
            catch (Exception ex)
            {
                bool rethrow = ExceptionPolicy.HandleException(ex, "Data Access Layer Policy");
                if (rethrow)
                {
                    throw;
                }
            }

            MarkOld();
        }

        internal void Update(Catalog catalog)
        {
            // if we're not dirty then don't update the database
            if (!this.IsDirty) return;
            
            Database db = DatabaseFactory.CreateDatabase("SiteWorx");
            DbCommand dbCommand = db.GetStoredProcCommand("aspnet_Products_UpdateProduct");
            db.AddInParameter(dbCommand, "ApplicationId", DbType.Guid, Site.GetSite().ApplicationId);
            db.AddInParameter(dbCommand, "ProductCatalogId", DbType.Int32, catalog.ID);
            db.AddInParameter(dbCommand, "ProductId", DbType.Int32, _id);
            db.AddInParameter(dbCommand, "Title", DbType.String, _title);
            db.AddInParameter(dbCommand, "Description", DbType.String, _description);
            db.AddInParameter(dbCommand, "ItemNumber", DbType.String, _itemNumber);
            db.AddInParameter(dbCommand, "Dimensions", DbType.String, _dimensions);
            db.AddInParameter(dbCommand, "UnitPrice", DbType.Currency, _unitPrice);
            db.AddInParameter(dbCommand, "ImagePath", DbType.String, _imagePath);
            db.AddInParameter(dbCommand, "Position", DbType.Int32, _position);
            db.AddInParameter(dbCommand, "LastUpdatedBy", DbType.Guid, Membership.User.GetUser(Thread.CurrentPrincipal.Identity.Name).ID);
            db.AddInParameter(dbCommand, "LastUpdatedDate", DbType.DateTime, DateTime.Now);

            try
            {
                db.ExecuteNonQuery(dbCommand);
                dbCommand.Dispose();
            }
            catch (Exception ex)
            {
                bool rethrow = ExceptionPolicy.HandleException(ex, "Data Access Layer Policy");
                if (rethrow)
                {
                    throw;
                }
            }
            
            MarkOld();
        }

        internal void DeleteSelf()
        {
            // if we're not dirty then don't update the database
            if (!this.IsDirty) return;

            // if we're new then don't update the database
            if (this.IsNew) return;

            Database db = DatabaseFactory.CreateDatabase("SiteWorx");
            DbCommand dbCommand = db.GetStoredProcCommand("aspnet_Products_RemoveProduct");
            db.AddInParameter(dbCommand, "ApplicationId", DbType.Guid, Site.GetSite().ApplicationId);
            db.AddInParameter(dbCommand, "ProductId", DbType.Int32, this.ID);

            try
            {
                db.ExecuteNonQuery(dbCommand);
                dbCommand.Dispose();
            }
            catch (Exception ex)
            {
                bool rethrow = ExceptionPolicy.HandleException(ex, "Data Access Layer Policy");
                if (rethrow)
                {
                    throw;
                }
            }

            MarkNew();
        }

        #endregion

    }
}
